package com.yueqian.xml.teachercode;

import org.w3c.dom.*;
import org.xml.sax.SAXException;

import javax.swing.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class ParseXMLTest {
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    public static void main(String[] args) {
        // 注意： Collections.EMPTY_LIST; 不能调用 .add() 等方法进行元素操作

        List<Account> accList = null;
        try {
            accList = parseAccXML("account.xml");
            System.out.println(accList);
        } catch (ParserConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        Account acc = new Account("小孙", 1200, "普通", new Date(), false);
        Account acc2 = new Account("小周", 2200, "高级", new Date(), true);
        accList.add(acc);
        accList.add(acc2);
        // 写xml文件
        writeXML(accList, "account.xml");
    }

    /**
     * 写xml文件
     */
    private static void writeXML(List<Account> accList, String xmlFilePath) {
        // 过滤非法
        if (accList == null || accList.isEmpty() || xmlFilePath == null || xmlFilePath.trim().isEmpty()) {
            throw new IllegalArgumentException();
        }
        // 检测文件是否存在
        File xmlFile = new File(xmlFilePath);
        if (xmlFile.exists()) {
            int sel = JOptionPane.showConfirmDialog(null, "文件已经存在，是否覆盖", "提示", JOptionPane.YES_NO_OPTION);
            // 如果选择否则退出
            if (sel == JOptionPane.NO_OPTION) {
                return;
            }
        }

        try {
            // 建立Document对象
            // (1) 获取DOM构建器的工厂实例；
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // (2)从工厂创建DOM构建器：
            DocumentBuilder builder = factory.newDocumentBuilder();
            // (3)使用构建器新建一个xml文档对象
            Document document = builder.newDocument();
            // 构建根 元素 节点
            Element root = document.createElement("accounts");
            // 添加元素节点到文档对象
            document.appendChild(root);
            // 构造不同的子节点
            for (Account acc : accList) {
                // 给每个Account对象构建一个acc元素节点
                Element accEle = document.createElement("acc");
                // 给acc元素节点上添加属性
                accEle.setAttribute("gender", acc.isGender() ? "男" : "女");
                // 添加名字节点
                addSubElement(document, "name", acc.getName(), accEle);
                // 添加余额节点
                addSubElement(document, "money", String.valueOf(acc.getMoney()), accEle);
                // 添加开户日期节点
                addSubElement(document, "accDate", sdf.format(acc.getAccDate()), accEle);
                // 添加账户类型节点
                addSubElement(document, "type", null, accEle, "typeName", acc.getType());
                //添加acc节点到根节点
                root.appendChild(accEle);
            }
            //将封装出来的树状xml结构模型写入文件
            //构造转换工厂
            TransformerFactory xmlFactory = TransformerFactory.newInstance();
            //根据转换工厂生成一个转换类
            Transformer tf = xmlFactory.newTransformer();
            //封装document到DOMSource的可以写模型
            DOMSource source = new DOMSource(document);
            //封装xml的写入结果流StreamResult对象
            StreamResult result = new StreamResult(xmlFile);
            //使用转换类将docment封装的DOMSource的可以写模型，写入结果流StreamResult，就生成了xml文件
            tf.transform(source, result);
        } catch (ParserConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (TransformerConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (TransformerException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    /**
     * 添加Account的属性元素节点
     */
    private static Element addSubElement(Document document, String tagName, String tagContent, Element parentEle) {
        // 过滤非法入参
        if (document == null || tagName == null || tagName.trim().isEmpty() || parentEle == null) {
            throw new IllegalArgumentException();
        }

        // 构建元素子节点
        Element ele = document.createElement(tagName);
        // 当有内容时构建文本子节点
        if (tagContent != null && !tagContent.trim().isEmpty()) {
            Text txtNode = document.createTextNode(tagContent);
            // 添加文本子节点到元素节点
            ele.appendChild(txtNode);
        }
        // 添加新建的元素子节点到父节点
        parentEle.appendChild(ele);

        return ele;
    }

    /**
     * 重载构建子元素的方法 添加Account的属性元素节点
     */
    private static void addSubElement(Document document, String tagName, String tagContent, Element parentEle,
                                      String attrName, String attrContent) {
        // 过滤非法入参
        if (attrName == null || attrName.trim().isEmpty() || attrContent == null || attrContent.trim().isEmpty()) {
            throw new IllegalArgumentException();
        }
        Element ele = addSubElement(document, tagName, tagContent, parentEle);
        ele.setAttribute(attrName, attrContent);
    }

    /**
     * 解析xml
     */
    public static List<Account> parseAccXML(String filePath)
            throws ParserConfigurationException, SAXException, IOException {
        List<Account> accList = new ArrayList<Account>();
        // 非法过滤
        File xmlFile = new File(filePath);
        if (!xmlFile.exists()) {
            return accList;
        }
        // (1) 获取DOM构建器的工厂实例；
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        // (2)从工厂创建DOM构建器：
        DocumentBuilder builder = factory.newDocumentBuilder();

        // (3)使用构建器对xml文件进行解析，获取文档对象节点：
        Document document = builder.parse(xmlFile);
        // (4)从文档对象节点中得到根元素节点：
        Element root = document.getDocumentElement();
        System.out.println(root.getNodeName());
        // (5)访问节点的属性、遍历子节点
        // 获取所有子节点.getChildNodes()
        NodeList nodeList = root.getChildNodes();
        // 遍历子节点（acc）； nodeList.getLength() 是获取子节点个数
        for (int i = 0; i < nodeList.getLength(); i++) {
            // 根据位置获取子节点 （acc）
            Node node = nodeList.item(i);
//			System.out.println(node.getNodeName()+":"+node.getNodeType());
            // 检测：当子节点是 acc标签的元素节点，是则获取，否则放过
            if ("acc".equals(node.getNodeName()) && node.getNodeType() == Node.ELEMENT_NODE) {
                // 强转为元素节点
                Element accEle = (Element) node;
                // 一个acc元素节点对应一个Account对象
                Account acc = new Account();
                // 获取属性
                acc.setGender("男".equals(accEle.getAttribute("gender")));
                // 获取子标签
                NodeList subNode = accEle.getChildNodes();
                // 循环获取
                for (int j = 0; j < subNode.getLength(); j++) {
                    Node fieldNode = subNode.item(j);
                    if ("name".equals(fieldNode.getNodeName())) {
                        // System.out.println("node
                        // value:"+fieldName.getChildNodes().item(0).getNodeValue());
                        acc.setName(fieldNode.getTextContent());
                    } else if ("money".equals(fieldNode.getNodeName())) {
                        if (!checkNum(fieldNode.getTextContent())) {
                            throw new IllegalArgumentException();
                        }
                        acc.setMoney(Double.parseDouble(fieldNode.getTextContent()));
                    } else if ("accDate".equals(fieldNode.getNodeName())) {
                        if (!checkDate(fieldNode.getTextContent())) {
                            throw new IllegalArgumentException();
                        }
                        acc.setAccDate(parseDate(fieldNode.getTextContent()));
                    } else if ("type".equals(fieldNode.getNodeName())) {
                        Element typeEle = (Element) fieldNode;
                        acc.setType(typeEle.getAttribute("typeName"));
                    }
                }
                // 添加acc到列表
                accList.add(acc);
            }
        }

        return accList;
    }

    public static boolean checkNum(String numStr) {
        if (numStr == null || numStr.trim().isEmpty()) {
            return false;
        }
        return numStr.matches("\\d*\\.?\\d*");
    }

    public static boolean checkDate(String dateStr) {
        if (dateStr == null || dateStr.trim().isEmpty()) {
            return false;
        }
        return dateStr.matches("\\d{4}\\-\\d{1,2}\\-\\d{1,2}");
    }

    public static Date parseDate(String dateStr) {

        try {
            return sdf.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

}
